/*
 * @Author: wuyuxin
 * @Date: 2022-01-12 10:56:25
 * @LastEditors: wuyuxin
 * @LastEditTime: 2022-01-12 14:33:11
 * @Description: 
 */

import { reroute } from "./reroute";

// hashChange, popstate
export const routingEventsListeningTo = ['hashChange', 'popstate'];

function urlReroute() {
  // console.log('urlReroute', arguments)
  reroute([], arguments) // 会根据路径重新加载不同的应用
}

const captureEventListeners = { // 后续挂载的事件先暂存起来
  hashChange: [],
  popstate: [], // 当应用切换完成后可以调用
}

// 我们处理应用加载的逻辑是在最前面
window.addEventListener('hashchange', urlReroute)
window.addEventListener('popstate', urlReroute)

const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;

window.addEventListener = function (eventName, fn) {
  if (routingEventsListeningTo.indexOf(eventName) >= 0 && !captureEventListeners[eventName].some(listener => listener == fn)) {
    captureEventListeners[eventName].push(fn);
    return
  }
  return originalAddEventListener.apply(this, arguments)
}
window.removeEventListener = function (eventName, fn) {
  if (routingEventsListeningTo.indexOf(eventName) >= 0) {
    captureEventListeners[eventName] = captureEventListeners[eventName].filter(l => l !== fn);
    return
  }
  return originalRemoveEventListener.apply(this, arguments)
}

// 如果是hash路由 hash变化时可以切换
// 浏览器路由，如果浏览器路由切换的是h5api, 切换时不会触发popstate

// 重写方法
function patchedUpdateState(updateState, methodName) {
  return function () {
    const urlBefore = window.location.href;
    const result = updateState.apply(this, arguments);
    const urlAfter = window.location.href;
    // console.log('patchedUpdateState', urlBefore, urlAfter)
    if (urlBefore !== urlAfter) {
      urlReroute(new PopStateEvent('popstate'))
    }
    return result;
  }
}

window.history.pushState = patchedUpdateState(window.history.pushState, 'pushState');
window.history.replaceState = patchedUpdateState(window.history.replaceState, 'replaceState');

// 用户可能会绑定自己的路由事件 vue

// 当我们应用切换后，还需要处理原来的方法， 需要在应用切换后再执行

// 在子应用加载完毕后调用此方法，执行拦截的逻辑（保证子应用加载完后执行）
export function callCapturedEventListeners(eventArguments) {
  if (eventArguments) {
      const eventType = eventArguments[0].type;
      if (routingEventsListeningTo.indexOf(eventType) >= 0) {
          capturedEventListeners[eventType].forEach((listener) => {
              listener.apply(this, eventArguments);
          });
      }
  }
}